package cn.zyx.file.minio.serivce;

import cn.zyx.common.GlobalExceptions;
import cn.zyx.common.utils.DateUtils;
import cn.zyx.common.utils.file.FileTypeUtils;
import cn.zyx.common.utils.file.FileUploadCommonUtils;
import cn.zyx.common.utils.file.FileUtils;
import cn.zyx.common.utils.snowflake.Seq;
import io.minio.*;
import io.minio.errors.MinioException;
import org.apache.commons.io.IOUtils;
import cn.zyx.config.minio.MinioConfig;
import cn.zyx.file.minio.entity.Minio;
import io.minio.http.Method;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class MinioService {

    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient client;

    @Value("${spring.profiles.active}")
    private String active;

    /**
     * Minio文件上传接口
     *
     * @param file 上传的文件
     * @return 访问地址
     * @throws Exception
     */
    public String uploadFile(MultipartFile file) throws Exception {
        // 获取文件名
        String fileName = FileUploadCommonUtils.extractFilename(file);
        InputStream inputStream = file.getInputStream();
        // 上传文件
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(active + "/" + fileName)
                .stream(inputStream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        // 关闭io流
        IOUtils.closeQuietly(inputStream);
        return active + "/" + fileName;
    }

    /**
     * 批量上传
     * @param fileList
     * @return
     * @throws Exception
     */
    public List<Minio> uploadList(List<MultipartFile> fileList) throws Exception {
        List<Minio> files = new ArrayList<>();
        for (MultipartFile file : fileList) {
            String s = active + "/" + DateUtils.datePath() + "/" +
                    FilenameUtils.getBaseName(file.getOriginalFilename()) + "." + FileTypeUtils.getExtension(file);
            InputStream inputStream = file.getInputStream();
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(s)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build();
            client.putObject(args);
            IOUtils.closeQuietly(inputStream);
            Minio minio = new Minio();
            minio.setName(FileUtils.getName(s));
            minio.setUrl(s);
            minio.setPath(generatePresignedUrl(s));
            files.add(minio);
        }
        return files;
    }

    /**
     * 返回公网显示的文件路径
     * @param filePath
     * @return
     */
    public String generatePresignedUrl(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            return "";
        }
        return minioConfig.getShowUrl() + minioConfig.getBucketName() + "/" + filePath;
    }

    /**
     * 返回公网app显示的文件路径
     * @param filePath
     * @return
     */
    public String generatePresignedUrlApp(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            return "";
        }
        return minioConfig.getShowAppUrl() + minioConfig.getBucketName() + "/" + filePath;
    }


    /**
     * 获取文件访问路径
     * @param bucketName    桶名称
     * @param minioFilePath 文件路径
     * @return 文件访问链接
     */
    private String getMinioFileUrl(String bucketName, String minioFilePath) throws Exception {
        if (StringUtils.isBlank(bucketName)) {
            bucketName = minioConfig.getBucketName();
        }
        return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(minioFilePath)
                .method(Method.GET)
                .expiry(1, TimeUnit.DAYS)
                .build()
        );
    }

    /**
     * base64 告警图片上传
     * @param file
     * @param deviceCode
     * @return
     * @throws Exception
     */
    public String uploadAlarmImgToOss(MultipartFile file, String deviceCode) throws Exception {
        String fileName = DateUtils.datePath() + "/" +
                deviceCode + "/" +
                FilenameUtils.getBaseName(file.getOriginalFilename()) + "_" +
                Seq.getId(Seq.uploadSeqType) + "." +
                FileTypeUtils.getExtension(file);
        InputStream inputStream = file.getInputStream();
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(active + "/alarm/" + fileName)
                .stream(inputStream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        IOUtils.closeQuietly(inputStream);
        return active + "/alarm/" + fileName;

    }

    /**
     * 删除文件
     * @param filePath
     * @throws Exception
     */
    public void deleteFile(String filePath) throws Exception {
        client.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(filePath).build());
    }

    /**
     * 文件上传
     *
     * @param file
     * @return
     * @throws Exception
     */
    public Minio uploadFile(File file) throws Exception {
        if (ObjectUtils.isEmpty(file)) {
            return new Minio();
        }
        MultipartFile multipartFile = FileUploadCommonUtils.getMultipartFile(file);
        String s = uploadFile(multipartFile);
        Minio Minio = new Minio();
        Minio.setName(FileUtils.getName(s));
        Minio.setUrl(s);
        Minio.setPath(generatePresignedUrl(s));
        Minio.setAppPath(generatePresignedUrlApp(s));
        return Minio;
    }

    /**
     * base64文件上传请求
     *
     * @param inputStream
     * @return
     * @throws Exception
     */
    public String uploadBase64(InputStream inputStream) throws Exception {
        String fileName = DateUtils.datePath() + "/" + Seq.getId(Seq.uploadSeqType) + "jpg";
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(active + "/" + fileName)
                .stream(inputStream, inputStream.available(), -1)
                .contentType(MediaType.IMAGE_PNG_VALUE)
                .build();
        client.putObject(args);
        IOUtils.closeQuietly(inputStream);
        return active + "/" + fileName;
    }

    /**
     * 下载文件并返回 InputStream
     */
    public InputStream downloadFile(String fileName) throws Exception {
        try {
            return client.getObject(
                    GetObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(fileName)
                            .build()
            );
        } catch (MinioException e) {
            throw new GlobalExceptions("MinIO 下载失败: " + e.getMessage());
        }
    }
}
